package com.hotel.BL;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.EntityName;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.EntityNotFoundException;
import com.google.appengine.api.datastore.FetchOptions;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.Query.CompositeFilterOperator;
import com.google.appengine.api.datastore.Query.Filter;
import com.google.appengine.api.datastore.Query.FilterOperator;
import com.google.appengine.api.datastore.Query.FilterPredicate;

import data.Reservation;
import data.RoomType;
import data.SubReservation;
import data.Tax;

public class RoomTypeLogic extends AbstractBL {
	
	public RoomTypeLogic(HttpServletRequest req,HttpServletResponse resp){
		this.req=req;
		this.resp=resp;
	}
	
	public List<RoomType> GenerateRoomType(long hotelId) throws EntityNotFoundException
	{
		List<Tax> taxlist = new TaxLogic(req,resp).GetAllTax(hotelId);
		
		List<RoomType> list = new ArrayList<RoomType>();
		
		if(GetRoomType(hotelId,"iSuite") == null)
		{
			RoomType roomtype = new RoomType();
			roomtype.setHotelId(hotelId);
			roomtype.setShortName("iSuite");
			roomtype.setStandardOccupancy(2);
			roomtype.setHigherOccupancy(5);
			roomtype.setExtraBedPrice(800);
			roomtype.setExtraBedAllowed((short) 2);
			roomtype.setBasePrice(1500);
			roomtype.setApplicableTaxListString(String.valueOf(taxlist.get(0).getId()));
			list.add(roomtype);
		}else{
			RoomType rt = GetRoomType(hotelId,"iSuite");
			rt.setApplicableTaxListString(String.valueOf(taxlist.get(0).getId()));
			UpdateRoomType(rt);
		}
		if(GetRoomType(hotelId,"iDeluxe King Bed") == null)
		{
			RoomType roomtype = new RoomType();
			roomtype = new RoomType();
			roomtype.setHotelId(hotelId);
			roomtype.setShortName("iDeluxe King Bed");
			roomtype.setStandardOccupancy(3);
			roomtype.setHigherOccupancy(6);
			roomtype.setExtraBedPrice(200);
			roomtype.setExtraBedAllowed((short) 5);
			roomtype.setBasePrice(1300);
			roomtype.setApplicableTaxListString(String.valueOf(taxlist.get(1).getId()));
			list.add(roomtype);
		}else{
			RoomType rt = GetRoomType(hotelId,"iDeluxe King Bed");
			rt.setApplicableTaxListString(String.valueOf(taxlist.get(1).getId()));
			UpdateRoomType(rt);
		}
		
		if(GetRoomType(hotelId,"iDeluxe Queen Bed") == null)
		{
			RoomType roomtype = new RoomType();
			roomtype = new RoomType();
			roomtype.setHotelId(hotelId);
			roomtype.setShortName("iDeluxe Queen Bed");
			roomtype.setStandardOccupancy(4);
			roomtype.setHigherOccupancy(8);
			roomtype.setExtraBedPrice(500);
			roomtype.setExtraBedAllowed((short) 8);
			roomtype.setBasePrice(1000);
			roomtype.setApplicableTaxListString(String.valueOf(taxlist.get(0).getId())+","+
					String.valueOf(taxlist.get(1).getId()));
			list.add(roomtype);
		}else{
			RoomType rt = GetRoomType(hotelId,"iDeluxe Queen Bed");
			rt.setApplicableTaxListString(String.valueOf(taxlist.get(0).getId())+","+
					String.valueOf(taxlist.get(1).getId()));
			UpdateRoomType(rt);
		}
		return list;
	}
	
	public RoomType GetRoomType(long id)
	{
		Key key = KeyFactory.createKey(EntityName.RoomType, id);
		try {
			Entity lang = datastore.get(key);
			RoomType c = new RoomType();
			c.setEntity(lang);
			return c;
		} catch (EntityNotFoundException e) {
			return null;
		}
	}
		
	public List<HashMap<String,Object>> OnlyIdAndTitle(List<RoomType> list){
		List<HashMap<String,Object>> data = new ArrayList<HashMap<String,Object>>();
		for(int i=0;i<list.size();i++){
			HashMap<String,Object> map = new HashMap<String, Object>();
			map.put("id", list.get(i).getId());
			map.put("title", list.get(i).getShortName());
			data.add(map);
		}
		return data;
	}
	
	public RoomType GetRoomType(long hotelId,String title)
	{
		Query q = new Query(EntityName.RoomType);
		
		Filter filterHotel = new FilterPredicate("hotelId",FilterOperator.EQUAL,hotelId);
		Filter filterStatus = new FilterPredicate("status",FilterOperator.EQUAL,true);
		Filter filterAvaliable = new FilterPredicate("avaliable",FilterOperator.EQUAL,true);
		Filter filterTitle = new FilterPredicate("shortName",FilterOperator.EQUAL,title);

		Filter filter = CompositeFilterOperator.and(filterHotel,filterStatus,filterAvaliable,filterTitle);
		
		q.setFilter(filter);
		
		return GetRoomType(datastore.prepare(q).asSingleEntity());
	}
	
	public List<RoomType> GetAllRoomType(long hotelId)
	{
		Query q = new Query(EntityName.RoomType);
		//String.valueOf(hotelId)
		Filter filterHotel = new FilterPredicate("hotelId",FilterOperator.EQUAL,hotelId);
		Filter filterStatus = new FilterPredicate("status",FilterOperator.EQUAL,true);
		Filter filterAvaliable = new FilterPredicate("avaliable",FilterOperator.EQUAL,true);

		Filter filter = CompositeFilterOperator.and(filterHotel, filterStatus, filterAvaliable);
		
		q.setFilter(filter);
		return GetList(datastore.prepare(q).asList(FetchOptions.Builder.withDefaults()));
	}

	public List<RoomType> GetAllRoomtype4AdminLimit(long hotelId,long offset,long line)
	{
		Query q = new Query(EntityName.RoomType);
		Filter filterHotel = new FilterPredicate("hotelId",FilterOperator.EQUAL,hotelId);
		Filter filterAvaliable = new FilterPredicate("avaliable",FilterOperator.EQUAL,true);

		Filter filter = CompositeFilterOperator.and(filterHotel, filterAvaliable);
		
		q.setFilter(filter);
		
		return GetList(datastore.prepare(q).asList(FetchOptions.Builder.withLimit((int) line).offset((int)offset)));
	}
	
	public List<RoomType> GetAllRoomtype4Admin(long hotelId)
	{
		Query q = new Query(EntityName.RoomType);
		Filter filterHotel = new FilterPredicate("hotelId",FilterOperator.EQUAL,hotelId);
		Filter filterAvaliable = new FilterPredicate("avaliable",FilterOperator.EQUAL,true);

		Filter filter = CompositeFilterOperator.and(filterHotel, filterAvaliable);
		
		q.setFilter(filter);
		
		return GetList(datastore.prepare(q).asList(FetchOptions.Builder.withDefaults()));
	}	
	
	public RoomType GetRoomType(Entity entity)
	{
		if(entity == null) return null;
		RoomType item = new RoomType();
		item.setEntity(entity);
		return item;
	}
	
	public List<RoomType> GetList(List<Entity> entities)
	{
		List<RoomType> list = new ArrayList<RoomType>();
		if(entities!=null)
		for(Entity e : entities)
		{
			RoomType a = new RoomType();
			a.setEntity(e);
			list.add(a);
		}
		return list;
	}

	public RoomType AddRoomtype(long hotelId,String title,String shortName,String imageCaption,long StandardOccupancy,
			long MaxOccupancy,long extraBedAllowed,String amenityListString,Double basePrice,
			Double extraBedPrice,String applicableTaxListString,long sortOrder,
			String pic,String description,double upcharge) throws EntityNotFoundException{
		RoomType r = new RoomType();
		r.setHotelId(hotelId);
		r.setTitle(title);
		r.setShortName(shortName);
		r.setPic(pic);
		r.setDescription(description);
		r.setImageCaption(imageCaption);
		r.setStandardOccupancy(StandardOccupancy);
		r.setHigherOccupancy(MaxOccupancy);
		r.setExtraBedAllowed(extraBedAllowed);
		r.setAmenityListString(amenityListString);
		r.setBasePrice(basePrice);
		r.setExtraBedPrice(extraBedPrice);
		r.setApplicableTaxListString(applicableTaxListString);
		r.setSortOrder(sortOrder);
		r.setAvaliable(true);
		r.setStatus(true);
		r.setUpchargeperson(upcharge);

		Key k = datastore.put(r.getEntity());
		r.setId(k.getId());
		r.setKey(k);

		return r;
	}

	public RoomType EditRoomtype(long roomtypeId,String title,String shortName,String imageCaption,long StandardOccupancy,
			long MaxOccupancy,long extraBedAllowed,String amenityListString,Double basePrice,
			Double extraBedPrice,String applicableTaxListString,String pic,String description,double upcharge) throws EntityNotFoundException{
		
		RoomType r = GetRoomType(roomtypeId);
		r.setTitle(title);
		r.setShortName(shortName);
		r.setDescription(description);
		r.setPic(pic);
		r.setImageCaption(imageCaption);
		r.setStandardOccupancy(StandardOccupancy);
		r.setHigherOccupancy(MaxOccupancy);
		r.setExtraBedAllowed(extraBedAllowed);
		r.setAmenityListString(amenityListString);
		r.setBasePrice(basePrice);
		r.setExtraBedPrice(extraBedPrice);
		r.setApplicableTaxListString(applicableTaxListString);
		r.setUpchargeperson(upcharge);

		Key k = datastore.put(r.getEntity());
		r.setId(k.getId());
		r.setKey(k);

		return r;
	}

	
	public RoomType DeleteRoomtype(long roomtypeId) throws EntityNotFoundException{
		
		RoomType r = GetRoomType(roomtypeId);
		r.setAvaliable(false);
		r.setStatus(false);
		
		Key k = datastore.put(r.getEntity());
		r.setId(k.getId());
		r.setKey(k);

		return r;
	}

	public RoomType ChangeStatus(long roomtypeId) throws EntityNotFoundException{
		
		RoomType a = GetRoomType(roomtypeId);
		if(a.isStatus() == true){
			a.setStatus(false);
		}else if(a.isStatus() == false){
			a.setStatus(true);
		}
		 
		Key k = datastore.put(a.getEntity());
		a.setId(k.getId());
		a.setKey(k);

		return a;
	}
	
	public RoomType EditSortOrder(long roomtypeId,long sortOrder) throws EntityNotFoundException{
		
		RoomType r = GetRoomType(roomtypeId);
		r.setSortOrder(sortOrder);

		Key k = datastore.put(r.getEntity());
		r.setId(k.getId());
		r.setKey(k);

		return r;
	}
	
	public RoomType EditUpchargeperson(long roomtypeId,double upchargecost) throws EntityNotFoundException{
		
		RoomType r = GetRoomType(roomtypeId);
		r.setUpchargeperson(upchargecost);

		Key k = datastore.put(r.getEntity());
		r.setId(k.getId());
		r.setKey(k);

		return r;
	}
	

	public RoomType UpdateRoomType(RoomType roomtype) throws EntityNotFoundException
	{
		Key key = datastore.put(roomtype.getEntity());
		roomtype.setId(key.getId());
		roomtype.setKey(key);
		return roomtype;
	}
	
	public RoomType EditPrice(long roomtypeId,double baseprice,double extraBedPrice,int exbedallowed) throws EntityNotFoundException{
		
		RoomType r = GetRoomType(roomtypeId);
		r.setBasePrice(baseprice);
		r.setExtraBedAllowed((short)exbedallowed);
		r.setExtraBedPrice(extraBedPrice);

		Key k = datastore.put(r.getEntity());
		r.setId(k.getId());
		r.setKey(k);

		return r;
	}
	
	public RoomType GetRoomTypeByDate(List<SubReservation> subres,Date date){
		for(int i = 0; i< subres.size();i++){
			if(!(date.before(subres.get(i).getDate()) || date.after(subres.get(i).getDateTo()) || date.equals(subres.get(i).getDateTo())))
				return subres.get(i).getRoomType();
		}
		return null;
	}
	
	public boolean CanChangeRoomType(long hotelId,long rtId){
		Query q = new Query(EntityName.Reservation);
		Date date = new NightAuditLogic(req,resp).ChangeToNightAuditTime(hotelId,new GenericLogic(req,resp).ServerDateTime());
		Filter filterhotelId = new FilterPredicate("hotelId",
				FilterOperator.EQUAL, hotelId);
		Filter filterDate = new FilterPredicate("dateTo",
				FilterOperator.GREATER_THAN_OR_EQUAL, date);
		Filter filter = CompositeFilterOperator.and(filterhotelId, filterDate);
		q.setFilter(filter);
		List<Reservation> list = new ReservationLogic(req,resp).GetList(datastore.prepare(q).asList(
				FetchOptions.Builder.withDefaults()));
		boolean isFoundUsed = false;
		for(int i=0;i<list.size();i++){
			if(list.get(i).getRoomType().getId() == rtId){
				isFoundUsed = true;
				break;
			}
		}
		return isFoundUsed;
	}
}
